/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ztb.android.livecubes.cube2;

import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BlurMaskFilter;
import android.graphics.BlurMaskFilter.Blur;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.EmbossMaskFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Shader;
import android.os.Handler;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

/*
 * This animated wallpaper draws a rotating wireframe shape. It is similar to
 * example #1, but has a choice of 2 shapes, which are user selectable and
 * defined in resources instead of in code.
 */

public class CubeWallpaper2 extends WallpaperService {

	public static final String SHARED_PREFS_NAME = "cube2settings";

	private Bitmap mBackground = null;
	
	static class ThreeDPoint {
		float x;
		float y;
		float z;
	}

	static class ThreeDLine {
		int startPoint;
		int endPoint;
	}

	@Override
	public void onCreate() {
		super.onCreate();
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
	}

	@Override
	public Engine onCreateEngine() {
		return new CubeEngine();
	}

	class CubeEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener {

		private final Handler mHandler = new Handler();

		ThreeDPoint[] mOriginalPoints;
		ThreeDPoint[] mRotatedPoints;
		ThreeDLine[] mLines;
		private final Paint mPaint = new Paint();
		private Path mPath = null;
		private float mPhase = 0;
		// private Shader mShader = new LinearGradient(0, 0, 10, 10, new int[] { Color.RED, Color.GREEN, Color.BLUE, Color.WHITE }, null, Shader.TileMode.REPEAT);

		private float mOffset;
		private float mTouchX = -1;
		private float mTouchY = -1;
		private long mStartTime;
		private float mCenterX;
		private float mCenterY;

		private final Runnable mDrawCube = new Runnable() {
			public void run() {
				drawFrame();
			}
		};
		private boolean mVisible;
		private SharedPreferences mPrefs;

		CubeEngine() {
			// Create a Paint to draw the lines for our cube
			final Paint paint = mPaint;
			paint.setColor(0xffffffff);
			paint.setAntiAlias(true);
			paint.setStrokeWidth(2);
			paint.setStrokeCap(Paint.Cap.ROUND);
			paint.setStyle(Paint.Style.STROKE);

			mStartTime = SystemClock.elapsedRealtime();

			mPrefs = CubeWallpaper2.this.getSharedPreferences(SHARED_PREFS_NAME, 0);
			mPrefs.registerOnSharedPreferenceChangeListener(this);
			onSharedPreferenceChanged(mPrefs, null);
		}

		public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {

			String shape = prefs.getString("cube2_shape", "cube");

			// read the 3D model from the resource
			readModel(shape);
		}

		private void readModel(String prefix) {
			// Read the model definition in from a resource.

			// get the resource identifiers for the arrays for the selected shape
			int pid = getResources().getIdentifier(prefix + "points", "array", getPackageName());
			int lid = getResources().getIdentifier(prefix + "lines", "array", getPackageName());

			String[] p = getResources().getStringArray(pid);
			int numpoints = p.length;
			mOriginalPoints = new ThreeDPoint[numpoints];
			mRotatedPoints = new ThreeDPoint[numpoints];

			for (int i = 0; i < numpoints; i++) {
				mOriginalPoints[i] = new ThreeDPoint();
				mRotatedPoints[i] = new ThreeDPoint();
				String[] coord = p[i].split(" ");
				mOriginalPoints[i].x = Float.valueOf(coord[0]);
				mOriginalPoints[i].y = Float.valueOf(coord[1]);
				mOriginalPoints[i].z = Float.valueOf(coord[2]);
			}

			String[] l = getResources().getStringArray(lid);
			int numlines = l.length;
			mLines = new ThreeDLine[numlines];

			for (int i = 0; i < numlines; i++) {
				mLines[i] = new ThreeDLine();
				String[] idx = l[i].split(" ");
				mLines[i].startPoint = Integer.valueOf(idx[0]);
				mLines[i].endPoint = Integer.valueOf(idx[1]);
			}
		}

		/**
		 * makeFollowPath
		 * 
		 * @return TODO
		 * @Description TODO
		 */
		private void makeFollowPath() {
			mPath = new Path();
			for (ThreeDPoint point : mOriginalPoints) {
				mPath.lineTo(point.x, point.y);
			}
			if (mPhase >= Float.MAX_VALUE) {
				mPhase = 0;
			}
			mPhase++;
			mPaint.setPathEffect(new DashPathEffect(new float[] { 4, 4, 4, 4 }, mPhase));

		}

		@Override
		public void onCreate(SurfaceHolder surfaceHolder) {
			super.onCreate(surfaceHolder);
			setTouchEventsEnabled(true);
		}

		@Override
		public void onDestroy() {
			super.onDestroy();
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onVisibilityChanged(boolean visible) {
			mVisible = visible;
			if (visible) {
				drawFrame();
			} else {
				mHandler.removeCallbacks(mDrawCube);
			}
		}

		@Override
		public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
			super.onSurfaceChanged(holder, format, width, height);
			// store the center of the surface, so we can draw the cube in the right spot
			mCenterX = width / 2.0f;
			mCenterY = height / 2.0f;
			drawFrame();
		}

		@Override
		public void onSurfaceCreated(SurfaceHolder holder) {
			super.onSurfaceCreated(holder);
		}

		@Override
		public void onSurfaceDestroyed(SurfaceHolder holder) {
			super.onSurfaceDestroyed(holder);
			mVisible = false;
			mHandler.removeCallbacks(mDrawCube);
		}

		@Override
		public void onOffsetsChanged(float xOffset, float yOffset, float xStep, float yStep, int xPixels, int yPixels) {
			mOffset = xOffset;
			drawFrame();
		}

		/*
		 * Store the position of the touch event so we can use it for drawing later
		 */
		@Override
		public void onTouchEvent(MotionEvent event) {
			if (event.getAction() == MotionEvent.ACTION_MOVE) {
				mTouchX = event.getX();
				mTouchY = event.getY();
			} else {
				mTouchX = -1;
				mTouchY = -1;
			}
			super.onTouchEvent(event);
		}

		/*
		 * Draw one frame of the animation. This method gets called repeatedly by posting a delayed Runnable. You can do any drawing you want in here. This example draws a wireframe cube.
		 */
		void drawFrame() {
			final SurfaceHolder holder = getSurfaceHolder();
			final Rect frame = holder.getSurfaceFrame();
			final int width = frame.width();
			final int height = frame.height();

			Canvas c = null;
			try {
				c = holder.lockCanvas();
				if (c != null) {
					// draw something
					makeFollowPath();
					c.drawPath(mPath, mPaint);
					drawCube(c);
					drawTouchPoint(c);
					drawTitle(c);
				}
			} finally {
				if (c != null)
					holder.unlockCanvasAndPost(c);
			}

			mHandler.removeCallbacks(mDrawCube);
			if (mVisible) {
				mHandler.postDelayed(mDrawCube, 1000 / 25);
			}
		}

		void drawTitle(Canvas c) {
			mPaint.setColor(Color.YELLOW);
			mPaint.setTextSize(50);
			
			float[] direction = new float[]{1,1,1};
			float light = 0.4f;
			float specular = 0.6f;
			float blur = 3.5f;
			EmbossMaskFilter emboss = new EmbossMaskFilter(direction, light, specular, blur);
			
			//new BlurMaskFilter(1, Blur.NORMAL)
			mPaint.setMaskFilter(emboss);
			c.drawText("love", mCenterX - 40, mCenterY, mPaint);
			mPaint.setMaskFilter(null);

		}

		void drawCube(Canvas c) {
			c.save();
			c.translate(mCenterX, mCenterY);
			c.drawColor(0xff000000);

			long now = SystemClock.elapsedRealtime();
			float xrot = ((float) (now - mStartTime)) / 1000;
			float yrot = (0.5f - mOffset) * 2.0f;
			rotateAndProjectPoints(0, xrot);
			drawLines(c);
			c.restore();
		}

		void rotateAndProjectPoints(float xrot, float yrot) {
			int n = mOriginalPoints.length;
			for (int i = 0; i < n; i++) {
				// rotation around X-axis
				ThreeDPoint p = mOriginalPoints[i];
				float x = p.x;
				float y = p.y;
				float z = p.z;
				float newy = (float) (Math.sin(xrot) * z + Math.cos(xrot) * y);
				float newz = (float) (Math.cos(xrot) * z - Math.sin(xrot) * y);

				// rotation around Y-axis
				float newx = (float) (Math.sin(yrot) * newz + Math.cos(yrot) * x);
				newz = (float) (Math.cos(yrot) * newz - Math.sin(yrot) * x);

				// 3D-to-2D projection
				float screenX = newx / (4 - newz / 400);
				float screenY = newy / (4 - newz / 400);

				mRotatedPoints[i].x = screenX;
				mRotatedPoints[i].y = screenY;
				mRotatedPoints[i].z = 0;
			}
		}

		void drawLines(Canvas c) {
			int n = mLines.length;
			for (int i = 0; i < n; i++) {
				ThreeDLine l = mLines[i];
				ThreeDPoint start = mRotatedPoints[l.startPoint];
				ThreeDPoint end = mRotatedPoints[l.endPoint];
				int kk = i % 7;
				if (kk == 0) {
					mPaint.setColor(Color.RED);
				} else if (kk == 1) {
					mPaint.setColor(Color.BLUE);
				} else if (kk == 2) {
					mPaint.setColor(0xFFFF0077);
				} else if (kk == 3) {
					mPaint.setColor(Color.CYAN);
				} else if (kk == 4) {
					mPaint.setColor(Color.YELLOW);
				} else if (kk == 5) {
					mPaint.setColor(Color.WHITE);
				} else if (kk == 6) {
					mPaint.setColor(Color.GREEN);
				}
				c.drawLine(start.x, start.y, end.x, end.y, mPaint);

			}
		}

		void drawTouchPoint(Canvas c) {
			if (mTouchX >= 0 && mTouchY >= 0) {
				c.drawCircle(mTouchX, mTouchY, 80, mPaint);
			}
		}
	}
}
